﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using DigitalRune.Windows.TextEditor;
using EmbeddedSharp.Core;
using Zove.DesignTime;
using Zove.Runtime;
using WeifenLuo.WinFormsUI.Docking;

namespace Zove.Desktop
{
    public partial class RunWindow : DockContent, IDesktopView
    {
        private ModelInstance sln = null;

        public EditingForm Editor
        {
            get;
            set;
        }

        public RunWindow()
        {
            InitializeComponent();
        }

        public RunWindow(string className)
        {
            this.InitializeComponent();

            this.ClassName = className;
            this.Text = className + " - for Run";

            this.sln = new ModelInstance(className);
            this.sln.Model = ZoveDependencyManager.Instance.RuntimeModelLoader.LoadByClassName(className);

            foreach (RuntimeFactor m in sln.Model.Factors)
            {
                this.gvSpace.Rows.Add(
                    new string[] { false.ToString(), m.Name, string.Empty });
            }

            this.ClassName = className;
        }

        public string ClassName {
            get;
            set;
        }

        public RunWindow(ZoomClass c)
        {
            this.InitializeComponent();

            this.ClassName = c.Name;
            this.Text = c.Name + " - for Run";

            this.sln = new ModelInstance(c);

            foreach (RuntimeFactor m in sln.Model.Factors)
            {
                this.gvSpace.Rows.Add(
                    new string[] { false.ToString(), m.Name, string.Empty });
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public void Validate()
        {
        }

        /// <summary>
        /// 
        /// </summary>
        public void Stop()
        {
        }

        /// <summary>
        /// 
        /// </summary>
        public void Run()
        {
            this.RunAsync();
        }

        /// <summary>
        /// 
        /// </summary>
        public RuntimeModel RuntimeModel {
            get;
            set;
        }

        /// <summary>
        /// 
        /// </summary>
        public void ClearInput()
        {
            foreach (DataGridViewRow r in this.gvSpace.Rows)
            {
                DataGridViewCell cell = r.Cells["colInput"];
                if (Convert.ToBoolean(cell.Value) == true)
                {
                    cell.Value = false;
                }
            }
        }

        public TextEditorControl GetTextEditorControl()
        {
            return new TextEditorControl();
        }

        public void OnKeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.F5)
            {
                this.RunAsync();
            }
        }

        private ZoomClass c = null;

        public void RunAsync()
        {
            if (this.Editor != null)
            {
                c = this.Editor.Class;
            }

            BackgroundWorker bw = new BackgroundWorker();
            bw.DoWork += new DoWorkEventHandler(Run);
            bw.RunWorkerCompleted
                += new RunWorkerCompletedEventHandler(RunComplete);

            bw.RunWorkerAsync();
        }

        private bool readyForEvaluate = true;

        public void Run(object sender, DoWorkEventArgs e)
        {
            Dictionary<string, string> w = new Dictionary<string, string>();
            if (this.Editor == null)
            {
                sln = new ModelInstance(this.ClassName);
            }
            else
            {
                sln = new ModelInstance(c);
            }

            bool ready = false;
            this.readyForEvaluate = true;
            foreach (DataGridViewRow r in this.gvSpace.Rows)
            {
                DataGridViewCell cell = r.Cells["colInput"];
                if (Convert.ToBoolean(cell.Value) == true)
                {
                    ready = true;
                    DataGridViewCell name = r.Cells["colName"];
                    DataGridViewCell value = r.Cells["colValue"];

                    if (string.IsNullOrEmpty(value.Value.ToString()))
                    {
                        readyForEvaluate = false;
                    }

                    this.sln.Initialize(
                        name.Value.ToString(), value.Value.ToString());
                }
            }

            if (ready)
            {
                sln.Evaluate();
            }
        }

        public void UpdatePrecision()
        {
            int precision = Utils.Precision;
            foreach(RuntimeFactor rf in sln.Model.Factors)
            {
                if (rf.Status != RuntimeFactorStatus.Unknown)
                {
                    rf.Value = Math.Round(rf.Value, precision);
                }
            }
        }

        public void RunComplete(object sender, RunWorkerCompletedEventArgs e)
        {
            while (this.gvSpace.Rows.Count > 0)
            {
                this.gvSpace.Rows.RemoveAt(0);
            }

            //if (this.readyForEvaluate)
            {
                //sln.Evaluate();
                UpdatePrecision();
            }

            foreach (RuntimeFactor m in sln.Model.Factors)
            {
                switch (m.Status)
                {
                    case RuntimeFactorStatus.Input:
                        this.gvSpace.Rows.Add(
                        new string[] { false.ToString(), 
                            m.Name, 
                            this.readyForEvaluate ? m.Value.ToString(): string.Empty, "<input>" });
                        break;
                    case RuntimeFactorStatus.Solved:
                        string expr =
                        ZoveDependencyManager.Instance.ExpressionTranslator.Translate(m.SolvedRule.Root);
                        this.gvSpace.Rows.Add(
                            new string[] { false.ToString(), 
                            m.Name, 
                            this.readyForEvaluate ? m.Value.ToString(): string.Empty, expr });
                        break;
                    case RuntimeFactorStatus.Unknown:
                        int rowId = this.gvSpace.Rows.Add(
                    new string[] { false.ToString(), 
                            m.Name, string.Empty, string.Empty });
                        this.gvSpace.Rows[rowId].DefaultCellStyle.ForeColor = Color.Red;
                        break;
                }
            }
        }

        public void Export(string fileName)
        {
            try
            {
                FileStream fs = new FileStream(fileName, FileMode.OpenOrCreate);
                StreamWriter sw = new StreamWriter(fs);

                foreach (RuntimeFactor m in this.sln.Model.Factors)
                {
                    string sol = string.Empty;

                    if (m.Status == RuntimeFactorStatus.Input)
                    {
                        sol = "<input>";
                    }
                    else if(m.SolvedRule.Root != null)
                    {
                        sol = ZoveDependencyManager.Instance.ExpressionTranslator.Translate(m.SolvedRule.Root);
                    }
                    else
                    {
                        sol = m.SolvedRule.Equation.Equation;
                    }

                    sw.WriteLine(
                        string.Format("{0}={1}:{2}", m.Name, m.Value, sol));
                }

                sw.Close();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        #region IDesktopWindow Members
        
        public string GetFileName() {
            return this.ClassName;
        }

        public string GetFileExtension() {
            return ".log";
        }

        public void Save(string fileName) {
            this.Export(fileName);
        }

        public string GetFileFilter() {
            return "Runtime Log File (*.log) | *.log";
        }

        public virtual string GetColourScheme() {
            return string.Empty;
        }

        public void RunInBackground()
        {
        }

        #endregion

        #region IDesktopForm Members


        public void Debug() {
            throw new NotImplementedException();
        }

        public void Resume() {
            throw new NotImplementedException();
        }

        public void Restart() {
            throw new NotImplementedException();
        }

        public double Profile() {
            throw new NotImplementedException();
        }

        #endregion
    }
}
